﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using DataProcessor.Core;
using LumenWorks.Framework.IO.Csv;
using LinqLib.Operators;
using LinqLib.Sequence;

namespace DataProcessor.FashionData
{
    public class FashionHitProcessor
    {
        string _processorPath;
        string _amtFinalFile, _perImageFile, _majorityFile;

        public List<Assignment> Assignments { get; private set; }
        public List<ImageInfo> Images { get; private set; }

        public static void Run()
        {
            var fhp = new FashionHitProcessor(@"D:\Data\Dropbox\University\Fashion10000\HIT Result");
            fhp.FlattenAssignment().MajorityVoting();
            //fhp.CalculateWorkersHitCount();

            //var fhpMMsys = new FashionHitProcessor(@"D:\Data\Dropbox\University\Fashion10000\MMSys");
            //fhpMMsys.FlattenAssignment();
        }
        
        public FashionHitProcessor(string processorPath)
        {
            _processorPath = processorPath;
            _amtFinalFile = processorPath + "\\ResultTest_200Batch.csv";
            _perImageFile = _processorPath + "\\Processed\\200Batch_PerImage_Experts.csv";
            _majorityFile = _processorPath + "\\Processed\\200Batch_MajorityVoting.csv";
            
            LoadAssignments();
        }

        private void LoadAssignments()
        {
            Assignments = new CsvReader(new StreamReader(_amtFinalFile), true).ToCsvDictionary()
                .Select(a => new Assignment(a)).ToList();

            Console.WriteLine(Assignments.Count + " assignments loaded...");
        }

        public FashionHitProcessor MarkRejectAssignments()
        {
            var rejectIds = Directory.GetFiles(_processorPath + "\\Reject")
                .Where(f => f.EndsWith("Final.csv"))
                .ToList()
                .SelectMany(f =>  
                    File.ReadAllLines(f).ToCsvDictionary().Select(i => i["AssignmentID"]))
                .Distinct();

            Assignments.Join(rejectIds, a => a.AssignmentId, r => r, (a, r) => a).ForEach(a => a.Approved = false);

            Console.WriteLine(rejectIds.Count() + " assignments have been rejected.");

            return this;
        }

        public FashionHitProcessor FlattenAssignment()
        {
            Images = Assignments.SelectMany(a => Enumerator.Range(1,1,4).Select(i => new ImageInfo(a, i))).ToList();

            var content = Images.Where(i => i.Approved).GroupBy(i => i.Url)
                .OrderBy(g => g.Key)
                .Select(g => String.Format("{0},{1},{2},{3},{4},{5},{6},{7}",
                    g.Key,
                    g.Select(i => i.Category).FirstOrDefault(),
                    g.Where(i => i.Related == "yes").Count(),
                    g.Where(i => i.Related == "no").Count(),
                    g.Where(i => i.Related == "notsure").Count(),
                    g.Where(i => i.Specialty == "yes").Count(),
                    g.Where(i => i.Specialty == "no").Count(),
                    g.Where(i => i.Specialty == "notsure").Count()
                ));

            var header = new string[] { "PictureURL,Category,Q1CountYes,Q1CountNo,Q1CountNotsure,Q2CountYes,Q2CountNo,Q2CountNotsure" };
            File.WriteAllLines(_perImageFile, header.Concat(content));

            Console.WriteLine("Assignmets flattend per image.");

            return this;
        }

        public FashionHitProcessor MajorityVoting()
        {
            var lines = File.ReadAllLines(_perImageFile);

            var output = lines.Skip(1).Select(line => new { Votes = new Votes(line.Split(',')), Data = line })
                .Select(item => String.Format("{0},{1},{2}", item.Data, item.Votes.MajorityQ1(), item.Votes.MajorityQ2()));

            var header = lines.Take(1).Select(line => line + ",Q1_Majority,Q2_Majority");

            File.WriteAllLines(_majorityFile, header.Concat(output));

            return this;
        }

        public void CalculateWorkersHitCount()
        {
            //var output = Assignments.GroupBy(a => a.HitId)
            //    .Select(g => g.OrderBy(a => a.SubmitTime).Skip(2).Take(1).SingleOrDefault())    // Select the first workers who did the HIT
            var output = Assignments.GroupBy(a => a.WorkerId)
                .OrderByDescending(g => g.Count())
                .Select(g => String.Format("{0},{1}", g.Key, g.Count()));

            string outputPath = _processorPath + "\\Processed\\WorkersHitCountAll.csv";
            var header = new string[] { "WorkerId,HitCount" };
            File.WriteAllLines(outputPath, header.Concat(output));
        }
    }
}
